﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Linq;

namespace BeardCoder.Data.Framework.NHibernate
{
    public class Repository<T> : IRepository<T> where T : class
    {
        private readonly ISessionFactory _sessionFactory;
        private readonly IDbContext _dbContext;

        public Repository(ISessionFactory sessionFactory)
        {
            if (sessionFactory == null) throw new ArgumentNullException("sessionFactory may not be null");

            _sessionFactory = sessionFactory;
            _dbContext = new DbContext(sessionFactory);
        }

        protected virtual ISession Session
        {
            get { return _sessionFactory.GetCurrentSession(); }
        }

        public virtual IDbContext DbContext
        {
            get { return _dbContext; }
        }

        public virtual void Add(T entity)
        {
            Session.Save(entity);
        }

        public void Update(T entity)
        {
            Session.Update(entity);
        }

        public void Delete(T entity)
        {
            Session.Delete(entity);
        }

        public void Delete(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            throw new NotImplementedException();
        }

        public T Get(object id)
        {
            return Session.Get<T>(id);
        }

        public T Get(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            return GetQueryable(where).FirstOrDefault();
        }

        public T Load(object id)
        {
            return Session.Load<T>(id);
        }

        public IEnumerable<T> List()
        {
            return List(null);
        }

        public IEnumerable<T> List(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            if (where != null)
                return GetQueryable().Where(where).ToList();
            return GetQueryable().ToList();
        }

        public IQueryable<T> GetQueryable()
        {
            return GetQueryable(null);
        }

        public IQueryable<T> GetQueryable(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            if (where != null)
                return Session.Query<T>().Where(where);
            return Session.Query<T>();
        }

        public IQueryable<K> GetQueryable<K>()
        {
            return Session.Query<K>();
        }

        public long Count()
        {
            return Count(null);
        }

        public long Count(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            return where != null ? GetQueryable(where).Count() : GetQueryable().Count();
        }

        public int SaveChanges()
        {
            DbContext.CommitChanges();
            return 1;
        }

        public bool IsModified(object entity)
        {
            return true;
        }

        public IUnitOfWork UnitOfWork
        {
            get { throw new NotImplementedException(); }
        }
    }
}
